import pygame
from pygame.locals import *
import time,random

'''
实现步骤：
1.创建游戏主窗口
2.处理键盘事件
3.创建玩家飞机
4.实现玩家飞机子弹发射
5.随机防止敌机
6.子弹与敌机碰撞检测
7.玩家与敌机碰撞检测，游戏结束
8.敌机发射子弹
9.敌机子弹碰撞检测，游戏结束
'''

# 游戏窗体大小
form_long = 512
form_high = 568

# 定义玩家类
class HeroPlane:
	def __init__(self,screen):
		self.x = 200
		self.y = 400
		self.image = pygame.image.load("./images/me.png")
		self.screen = screen
		self.bullet_list = []

	def display(self):
		''' 
			1.玩家飞机图片绘制到主窗体上 
			2.玩家发射的子弹绘制到窗口上
		'''
		for bullet in self.bullet_list:
			bullet.display()
			# 子弹移出画面时将其删除，释放资源
			if bullet.move():
				self.bullet_list.remove(bullet)

		self.screen.blit(self.image,(self.x,self.y))

	def fire(self):
		''' 将子弹装入弹夹 '''
		self.bullet_list.append(Bullet(self.screen,self.x,self.y))

	def move_left(self):
		''' 向左移动 '''
		# 防止移出左侧边界
		self.x -= 10
		if self.x <= 0:
			self.x = 0

	def move_right(self):
		''' 向右移动 '''
		# 防止移出右侧边界
		self.x += 10
		if self.x >= form_long-106: # 主窗体宽度减去飞机宽度
			self.x = form_long-106
# 子弹类
class Bullet:
	def __init__(self,screen,x,y):
		self.x = x+53
		self.y = y
		self.screen = screen
		self.image = pygame.image.load("./images/pd.png")

	def display(self):
		''' 绘制子弹 '''
		self.screen.blit(self.image,(self.x,self.y))

	def move(self):
		self.y -= 10
		if self.y <= -17: # 子弹的分辨率为3*17，此时说明子弹刚好从画面消失
			return True
		else:
			return False

# 敌机子弹类
class EnemyBullet(Bullet):
	def __init__(self,screen,x,y,enemylong,enemyhigh):
		# 保证子弹出现在敌机机头中间位置
		self.x = x+enemylong/2
		self.y = y+enemyhigh
		self.screen = screen
		self.image = pygame.image.load("./images/enemy_bullet.png")
	
	def move(self):
		self.y += 6
		if self.y >= form_high:
			return True

# 敌机类
class EnemyPlane:
	def __init__(self,screen):
		# 从x坐标任意位置随机一个敌机，注意不要超出窗体左右边界，y坐标保证在窗口画面外产生敌机
		self.x = random.choice(range(408))
		self.y = -75
		self.screen = screen
		self.bullet_list = []
		# 随机加载一个敌机图片
		random_num = random.choice(range(3))
		self.image = pygame.image.load("./images/e"+str(random_num)+".png")
		if random_num == 0:
			self.long = 116
			self.high = 82
		elif random_num == 1:
			self.long = 98
			self.high = 76
		elif random_num == 2:
			self.long = 104
			self.high = 74
		else:
			pass

	def display(self):
		''' 在窗口上绘制敌机 '''
		self.screen.blit(self.image,(self.x,self.y))
		# 随机发射子弹
		self.fire()
		for bullet in self.bullet_list:
			bullet.display()
			if bullet.move():
				self.bullet_list.remove(bullet)

	def fire(self):
		if random.choice(range(50)) == 10:
			self.bullet_list.append(EnemyBullet(self.screen,self.x,self.y,self.long,self.high))

	def move(self,hero):
		''' 敌机移动 '''
		# 返回列表，元素一代表敌机被子弹击中或已飞出画面，元素二代表敌机与玩家碰撞或玩家被敌机击中
		ret_list = [0,0]

		self.y += 3
		if self.y >= form_high: # 已移出窗口画面
			ret_list[0] = 1
			return ret_list
		# 敌机与玩家子弹碰撞检测
		for bullet in hero.bullet_list:
			if bullet.x > self.x+10 and bullet.x < self.x+95 and bullet.y > self.y+10 and bullet.y < self.y+70:
				# 显示爆炸效果
				boom = Boom(self.screen,bullet.x,bullet.y)
				boom.display()
				hero.bullet_list.remove(bullet)
				ret_list[0] = 1
				return ret_list
		# 玩家与敌机子弹碰撞检测
		for b in self.bullet_list:
			if b.x > hero.x+10 and b.x<hero.x+95 and b.y > hero.y+10:
				ret_list = [1,1]
				return ret_list
		# 飞机碰撞检测
		if hero.x > self.x+10-106 and hero.x < self.x+95 and hero.y > self.y+10 and hero.y < self.y+70:
			boom = Boom(self.screen,self.x,self.y)
			boom.display()
			ret_list = [1,1]
			return ret_list
		return ret_list

# 爆炸效果
class Boom:
	def __init__(self,screen,x,y):
		self.x = x-64
		self.y = y-64
		self.screen = screen
		self.image = pygame.image.load("./images/boom2.png")

	def display(self):
		self.screen.blit(self.image,(self.x,self.y))

def key_control(hero):
	''' 键盘事件处理 '''
	# 获取事件
	for event in pygame.event.get():
		if event.type == QUIT:
			exit()

	# 获取所有键盘按钮状态
	pressed_keys = pygame.key.get_pressed()

	# 左键和a键向左移动
	if pressed_keys[K_LEFT] or pressed_keys[K_a]:
		hero.move_left()
	# 右键和d键向右移动
	if pressed_keys[K_RIGHT] or pressed_keys[K_d]:
		hero.move_right()
	# 空格，开炮
	if pressed_keys[K_SPACE]:
		hero.fire()


def main():
	# 创建游戏窗口
	screen = pygame.display.set_mode((form_long,form_high),0,0)

	# 设置窗口标题
	pygame.display.set_caption("飞机大战")
	# 加载游戏背景 
	background = pygame.image.load("./images/bg2.jpg")
	# 加载游戏结束时的提示图
	over_image = pygame.image.load("./images/over.jpg")

	# 创建玩家飞机
	hero = HeroPlane(screen)
	# 敌机列表
	enemy_list = []

	# 游戏结束标志
	bOver = False

	y = -968 # 背景图左上角y坐标
	while True:
		# 绘制画面 
		screen.blit(background,(0,y))
		
		# 不断让背景图片向下滚动
		y += 2
		if y >= -200:
			y = -968

		# 主窗体上显示玩家飞机
		hero.display()

		if random.choice(range(60)) == 10:
			enemy_list.append(EnemyPlane(screen))
		for enemy in enemy_list:
			enemy.display()
			ret_list = enemy.move(hero)
			if ret_list[0]: # 敌机飞出画面或被子弹击中，销毁敌机
				enemy_list.remove(enemy)
			if ret_list[1]: # 玩家与敌机碰撞，游戏结束
				print("game over...") # 弹窗提示游戏结束
				bOver = True

		# 键盘事件处理
		key_control(hero)

		# 更新显示
		if bOver: # 游戏结束，显示一个game over画面,置于游戏窗体中间位置
			screen.blit(over_image,(form_long/2-250/2,form_high/2)) 
		pygame.display.update()

		# 定时显示画面
		time.sleep(0.04)
	
	# 更新显示
	pygame.display.update()

# 作为主运行程序
if __name__ == "__main__":
	main()